Skip to content

如何在發佈 ASP.NET Core 網站時自動套用 Shadow Copying 設定

TLDR

  • Shadow Copying 可解決 ASP.NET Core 執行時 DLL 被鎖定導致無法更新的問題。
  • 透過在專案根目錄預置 web.config,發佈時會自動合併設定,無需手動修改伺服器檔案。
  • 建議使用 dotnet publish 指令結合 web.config 預置,實現 CI/CD 自動化部署。
  • Hosting Bundle 7.0+ 使用 enableShadowCopy;6.0 版本則需使用 experimentalEnableShadowCopy
  • Shadow Copying 機制會自動清理舊資料夾,並非版本管理工具,不應依賴其保留舊版本。
  • 升級 .NET 版本後務必手動清理 Shadow Copying 資料夾,否則會觸發 500.30 錯誤。
  • 應避免在應用程式目錄內寫入檔案或 Log,以免頻繁觸發不必要的應用程式重啟。

解決發佈時 DLL 鎖定問題

什麼情況下會遇到這個問題: 當 Web 應用程式正在運行時,IIS 會鎖定相關 DLL 檔案,導致部署新版本時無法覆蓋檔案,必須手動停止應用程式集區。

Shadow Copying(陰影複製)機制會將應用程式檔案複製到暫存位置執行,從而釋放原始部署目錄的鎖定狀態。傳統做法是手動修改伺服器上的 web.config,但這不適合 CI/CD 流程。

最佳實踐是在專案根目錄預先建立 web.config,發佈時系統會自動將其作為基礎進行合併。

設定範例

在專案根目錄的 web.config 中加入 handlerSettings

xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath="dotnet" arguments=".\WebApi.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess">
        <handlerSettings>
          <handlerSetting name="enableShadowCopy" value="true" />
          <handlerSetting name="shadowCopyDirectory" value="../ShadowCopy/" />
        </handlerSettings>
      </aspNetCore>
    </system.webServer>
  </location>
</configuration>

若需同時設定環境變數(如 ASPNETCORE_ENVIRONMENT),可直接在 .pubxml 中設定,發佈後會自動合併至 web.config

xml
<EnvironmentName>Staging</EnvironmentName>

執行發佈指令:

bash
dotnet publish -c Release -p:EnvironmentName=Staging

版本差異

  • Hosting Bundle 7.0.0 以上:使用 enableShadowCopy 參數。
  • Hosting Bundle 6.0.0:使用 experimentalEnableShadowCopy 參數。

關於 Shadow Copying 的資料夾管理機制

什麼情況下會遇到這個問題: 當開發者誤以為 Shadow Copying 會自動維護多個版本供回滾使用時。

根據 AspNetCoreModuleV2 原始碼分析,Shadow Copying 的設計並非版本管理工具。當系統選定一個新的流水號資料夾作為執行路徑後,會啟動執行緒刪除該目錄下所有其他的資料夾。若發現目錄內有多個資料夾並存,通常是清理執行緒尚未完成,或是舊檔案被鎖定導致刪除失敗。

注意事項

  • 升級 .NET 版本:升級後必須手動刪除舊的 Shadow Copying 資料夾,否則會導致 IIS 出現 500.30 錯誤,事件檢視器會顯示 directory_iterator 找不到路徑的異常。
  • 避免寫入檔案:應避免在應用程式目錄中寫入檔案或 Log,否則每次檔案異動都可能觸發 Shadow Copying 機制,導致應用程式不必要的重啟。

異動歷程

    • 初版文件建立。
    • 補充升級 .NET 版本造成 Shadow Copying 異常。
    • 補充使用 Shadow Copying 時需避免在應用程式目錄寫入檔案的注意事項。
    • 補充 Shadow Copying 資料夾管理機制的常見誤解與源碼說明。